
#pragma once

extern CPoint g_DPI;

class CDPIForm
{
public:
	static void init();
	__forceinline static double SCALEX()
	{
		if (g_DPI.x == USER_DEFAULT_SCREEN_DPI) return 1.0;
		return (double)g_DPI.x / USER_DEFAULT_SCREEN_DPI;
	}
	__forceinline static double SCALEY()
	{
		if (g_DPI.y == USER_DEFAULT_SCREEN_DPI) return 1.0;
		return (double)g_DPI.y / USER_DEFAULT_SCREEN_DPI;
	}
	__forceinline static int DPIX(int x)
	{
		if (g_DPI.x == USER_DEFAULT_SCREEN_DPI) return x;
		return x >= 0 ? MulDiv(x, g_DPI.x, USER_DEFAULT_SCREEN_DPI) : (-DPIX(-x));
	}
	__forceinline static int DPIY(int y)
	{
		if (g_DPI.y == USER_DEFAULT_SCREEN_DPI) return y;
		return y >= 0 ? MulDiv(y, g_DPI.y, USER_DEFAULT_SCREEN_DPI) : (-DPIY(-y));
	}
	__forceinline static int NormalX(int x)
	{
		if (g_DPI.x == USER_DEFAULT_SCREEN_DPI) return x;
		return x >= 0 ? MulDiv(x, USER_DEFAULT_SCREEN_DPI, g_DPI.x) : (-NormalX(-x));
	}
	__forceinline static int NormalY(int y)
	{
		if (g_DPI.y == USER_DEFAULT_SCREEN_DPI) return y;
		return y >= 0 ? MulDiv(y, USER_DEFAULT_SCREEN_DPI, g_DPI.y) : (-NormalY(-y));
	}
	static void DPI(CRect &r);
	static void DPI(CPoint &p);
	static bool DPIScale(CBitmap &bitmap, int scale = 1);
	static bool DPIScale(HBITMAP &hBitmap, int scale = 1);
	static bool DPIScale(HICON &hIcon, int scale = 1);
	static HBITMAP DPICopy(HBITMAP hBitmap, int scale = 1);
	static HICON DPICopy(HICON hIcon, int scale = 1);

	CDPIForm(CWnd *pWnd, int mw = 0, int mh = 0);

	__forceinline CDPIForm &ctrl(CWnd &control, BOOL repaint = FALSE){ m_pCtrl = &control; repaintCtrl = repaint; return *this; }
	__forceinline CDPIForm &ctrl(int idCtrl, BOOL repaint = FALSE){ m_pCtrl = m_pWnd->GetDlgItem(idCtrl); repaintCtrl = repaint; return *this; }
	CDPIForm &resizeWindow(const CWnd *pRightCtrl, const CWnd *pBottomCtrl, int extendX = 0, int extendY = 0);
	CDPIForm &left(int x = 0, bool resize = false){ return setLeft(getWindowLeft(x), false, resize); }
	CDPIForm &setLeft(int x, bool needDPI, bool resize = false);
	CDPIForm &right(int x = 0, bool resize = false){ return setRight(getWindowRight(x), false, resize); }
	CDPIForm &setRight(int x, bool needDPI, bool resize = false);
	CDPIForm &top(int y = 0, bool resize = false){ return setTop(getWindowTop(y), false, resize); }
	CDPIForm &setTop(int y, bool needDPI, bool resize = false);
	CDPIForm &bottom(int y = 0, bool resize = false){ return setBottom(getWindowBottom(y), false, resize); }
	CDPIForm &setBottom(int y, bool needDPI, bool resize = false);
	CDPIForm &fullWindowSize();
	CDPIForm &after(const CWnd &ctrlAfter, int offsetx = 0, bool resize = false);
	CDPIForm &before(const CWnd &ctrlBefore, int offsetx = 0, bool resize = false);
	CDPIForm &below(const CWnd &ctrlBelow, int offsety = 0, bool resize = false);
	CDPIForm &above(const CWnd &ctrlAbove, int offsety = 0, bool resize = false);
	CDPIForm &alignLeft(const CWnd &ctrlAlign, int offsetx = 0, bool resize = false);
	CDPIForm &alignRight(const CWnd &ctrlAlign, int offsetx = 0, bool resize = false);
	CDPIForm &alignTop(const CWnd &ctrlAlign, int offsety = 0, bool resize = false);
	CDPIForm &alignBottom(const CWnd &ctrlAlign, int offsety = 0, bool resize = false);
	CDPIForm &centerX();
	CDPIForm &centerY();
	CDPIForm &centerX(const CWnd &ctrlAlign);
	CDPIForm &centerY(const CWnd &ctrlAlign);
	CDPIForm &centerX(int n, const CWnd *pCtrlAlign, ...);
	CDPIForm &centerY(int n, const CWnd *pCtrlAlign, ...);
	CDPIForm &centerX(int n, int idCtrlAlign, ...);
	CDPIForm &centerY(int n, int idCtrlAlign, ...);
	CDPIForm &centerXtoCtrl(int n, CWnd *pCtrlAlign, ...);
	CDPIForm &centerYtoCtrl(int n, CWnd *pCtrlAlign, ...);
	CDPIForm &centerXtoCtrl(int n, int idCtrlAlign, ...);
	CDPIForm &centerYtoCtrl(int n, int idCtrlAlign, ...);
	CDPIForm &SizeToContent();
	CDPIForm &GetSpaceRect(CRect &r, bool isCenter, int index = 0);
	CDPIForm &setWidth(int width, bool needDPI);
	CDPIForm &setHeight(int height, bool needDPI);
	CDPIForm &setSize(int width, int height, bool needDPI);
	CDPIForm &setPercentWidth(double width);
	CDPIForm &setPercentHeight(double height);
	CDPIForm &setPercentSize(double width, double height);
	CDPIForm &moveToX(int x, bool needDPI);
	CDPIForm &moveToY(int y, bool needDPI);
	CDPIForm &moveToXY(int x, int y, bool needDPI);
	bool getContentSize(CSize &sz) const;
	bool getTextSize(CSize &sz) const;
	bool getTextSize(CString &text, CSize &sz) const;
	CWnd * getMaxWidth(int n, CWnd *pCtrlAlign, ...) const;
	CWnd * getMaxWidth(int n, int idCtrlAlign, ...) const;
	CWnd * getMaxHeight(int n, CWnd *pCtrlAlign, ...) const;
	CWnd * getMaxHeight(int n, int idCtrlAlign, ...) const;

	__forceinline void GetRect(const CWnd &ctrl, CRect &r) const{ ctrl.GetWindowRect(&r); m_pWnd->ScreenToClient(&r); }
	__forceinline void GetRect(CRect &r) const{ m_pCtrl->GetWindowRect(&r); m_pWnd->ScreenToClient(&r); }
	__forceinline int getTop(int y = 0) const{ CRect r; GetRect(r); return r.top + DPIY(y); }
	__forceinline int getBottom(int y = 0) const{ CRect r; GetRect(r); return r.bottom + DPIY(y); }
	__forceinline int getLeft(int x = 0) const{ CRect r; GetRect(r); return r.left + DPIX(x); }
	__forceinline int getRight(int x = 0) const{ CRect r; GetRect(r); return r.right + DPIX(x); }
	__forceinline int getWidth() const{ CRect r; GetRect(r); return r.Width(); }
	__forceinline int getHeight() const{ CRect r; GetRect(r); return r.Height(); }
	__forceinline CSize getSize() const { CRect r; GetRect(r); return r.Size(); }
	__forceinline int getWindowTop(int y = 0) const{ CRect r; m_pWnd->GetClientRect(r); return r.top + DPIY(marginHeight + y); }
	__forceinline int getWindowBottom(int y = 0) const{ CRect r; m_pWnd->GetClientRect(r); return r.bottom - DPIY(marginHeight - y); }
	__forceinline int getWindowLeft(int x = 0) const{ CRect r; m_pWnd->GetClientRect(r); return r.left + DPIX(marginWidth + x); }
	__forceinline int getWindowRight(int x = 0) const{ CRect r; m_pWnd->GetClientRect(r); return r.right - DPIX(marginWidth - x); }
	__forceinline int getGroupLeft(int x = 0){ return getLeft(8); }
	__forceinline int getGroupTop(int y = 0){ return getTop(20); }
	__forceinline int getFrameTop(int y = 0){ return getTop(14); }
	__forceinline int getGroupRight(int x = 0){ return getRight(-8); }
	__forceinline int getGroupBottom(int y = 0){ return getBottom(-8); }
	__forceinline CDPIForm &resizeWindow(int idRightCtrl, const CWnd *pBottomCtrl, int extendX = 0, int extendY = 0)
	{
		return resizeWindow(idRightCtrl ? m_pWnd->GetDlgItem(idRightCtrl) : nullptr, pBottomCtrl, extendX, extendY);
	}
	__forceinline CDPIForm &resizeWindow(const CWnd *pRightCtrl, int idBottomCtrl, int extendX = 0, int extendY = 0)
	{
		return resizeWindow(pRightCtrl, idBottomCtrl ? m_pWnd->GetDlgItem(idBottomCtrl) : nullptr, extendX, extendY);
	}
	__forceinline CDPIForm &resizeWindow(int idRightCtrl, int idBottomCtrl, int extendX = 0, int extendY = 0)
	{
		return resizeWindow(idRightCtrl ? m_pWnd->GetDlgItem(idRightCtrl) : nullptr, idBottomCtrl ? m_pWnd->GetDlgItem(idBottomCtrl) : nullptr, extendX, extendY);
	}
	__forceinline CDPIForm &alignWidth(const CWnd &ctrlAlign, int offsetx = 0){ return alignLeft(ctrlAlign, -offsetx).alignRight(ctrlAlign, offsetx, true); }
	__forceinline CDPIForm &alignHeight(const CWnd &ctrlAlign, int offsety = 0){ return alignTop(ctrlAlign, -offsety).alignBottom(ctrlAlign, offsety, true); }
	__forceinline CDPIForm &after(int idCtrlAfter, int offsetx = 0, bool resize = false){ return after(*m_pWnd->GetDlgItem(idCtrlAfter), offsetx, resize); }
	__forceinline CDPIForm &before(int idCtrlBefore, int offsetx = 0, bool resize = false){ return before(*m_pWnd->GetDlgItem(idCtrlBefore), offsetx, resize); }
	__forceinline CDPIForm &below(int idCtrlBelow, int offsety = 0, bool resize = false){ return below(*m_pWnd->GetDlgItem(idCtrlBelow), offsety, resize); }
	__forceinline CDPIForm &above(int idCtrlAbove, int offsety = 0, bool resize = false){ return above(*m_pWnd->GetDlgItem(idCtrlAbove), offsety, resize); }
	__forceinline CDPIForm &alignLeft(int idCtrlAlign, int offsetx = 0, bool resize = false){ return alignLeft(*m_pWnd->GetDlgItem(idCtrlAlign), offsetx, resize); }
	__forceinline CDPIForm &alignRight(int idCtrlAlign, int offsetx = 0, bool resize = false){ return alignRight(*m_pWnd->GetDlgItem(idCtrlAlign), offsetx, resize); }
	__forceinline CDPIForm &alignTop(int idCtrlAlign, int offsety = 0, bool resize = false){ return alignTop(*m_pWnd->GetDlgItem(idCtrlAlign), offsety, resize); }
	__forceinline CDPIForm &alignBottom(int idCtrlAlign, int offsety = 0, bool resize = false){ return alignBottom(*m_pWnd->GetDlgItem(idCtrlAlign), offsety, resize); }
	__forceinline CDPIForm &centerX(int idCtrlAlign){ return centerX(*m_pWnd->GetDlgItem(idCtrlAlign)); }
	__forceinline CDPIForm &centerY(int idCtrlAlign){ return centerY(*m_pWnd->GetDlgItem(idCtrlAlign)); }
	__forceinline CDPIForm &alignWidth(int idCtrlAlign, int offsetx = 0){ return alignWidth(*m_pWnd->GetDlgItem(idCtrlAlign), offsetx); }
	__forceinline CDPIForm &alignHeight(int idCtrlAlign, int offsety = 0){ return alignHeight(*m_pWnd->GetDlgItem(idCtrlAlign), offsety); }

	__forceinline CDPIForm &groupLeft(const CWnd &group, int x = 0, bool resize = false){ return alignLeft(group, x + 8, resize); }
	__forceinline CDPIForm &groupTop(const CWnd &group, int y = 0, bool resize = false){ return alignTop(group, y + 20, resize); }
	__forceinline CDPIForm &frameTop(const CWnd &group, int y = 0, bool resize = false){ return alignTop(group, y + 14, resize); }
	__forceinline CDPIForm &groupRight(const CWnd &group, int x = 0, bool resize = false){ return alignRight(group, x - 8, resize); }
	__forceinline CDPIForm &groupBottom(const CWnd &group, int y = 0, bool resize = false){ return alignBottom(group, y - 8, resize); }
	__forceinline CDPIForm &groupLeft(int idGroup, int x = 0, bool resize = false){ return alignLeft(idGroup, x + 8, resize); }
	__forceinline CDPIForm &groupTop(int idGroup, int y = 0, bool resize = false){ return alignTop(idGroup, y + 20, resize); }
	__forceinline CDPIForm &frameTop(int idGroup, int y = 0, bool resize = false){ return alignTop(idGroup, y + 14, resize); }
	__forceinline CDPIForm &groupRight(int idGroup, int x = 0, bool resize = false){ return alignRight(idGroup, x - 8, resize); }
	__forceinline CDPIForm &groupBottom(int idGroup, int y = 0, bool resize = false){ return alignBottom(idGroup, y - 8, resize); }
	__forceinline CDPIForm &resizeGroup(const CWnd *pRightCtrl, const CWnd *pBottomCtrl, int extendX = 0, int extendY = 0)
	{
		if (pRightCtrl) alignRight(*pRightCtrl, extendX + 8, true);
		if (pBottomCtrl) alignBottom(*pBottomCtrl, extendY + 8, true);
		return *this;
	}
	__forceinline CDPIForm &resizeGroup(int idRightCtrl, const CWnd *pBottomCtrl, int extendX = 0, int extendY = 0)
	{
		if (idRightCtrl) alignRight(idRightCtrl, extendX + 8, true);
		if (pBottomCtrl) alignBottom(*pBottomCtrl, extendY + 8, true);
		return *this;
	}
	__forceinline CDPIForm &resizeGroup(const CWnd *pRightCtrl, int idBottomCtrl, int extendX = 0, int extendY = 0)
	{
		if (pRightCtrl) alignRight(*pRightCtrl, extendX + 8, true);
		if (idBottomCtrl) alignBottom(idBottomCtrl, extendY + 8, true);
		return *this;
	}
	__forceinline CDPIForm &resizeGroup(int idRightCtrl, int idBottomCtrl, int extendX = 0, int extendY = 0)
	{
		if (idRightCtrl) alignRight(idRightCtrl, extendX + 8, true);
		if (idBottomCtrl) alignBottom(idBottomCtrl, extendY + 8, true);
		return *this;
	}

	CDPIForm(CTabCtrl &tab, int nItem = 0);
	CDPIForm &fullTabSize();
	CDPIForm &getTabSize(CRect &r);
	CDPIForm &resizeTabWidth(const CWnd &ctrl, BOOL repaint = FALSE);
	CDPIForm &resizeTabHeight(const CWnd &ctrl, BOOL repaint = FALSE);
	CDPIForm &resizeTab(const CWnd &ctrl, BOOL repaint = FALSE);
	CDPIForm &tabLeft(int x = 0, bool resize = false);
	CDPIForm &tabTop(int y = 0, bool resize = false);
	CDPIForm &tabRight(int x = 0, bool resize = false);
	CDPIForm &tabBottom(int y = 0, bool resize = false);
public:
	int edgeTop, edgeBottom, edgeLeft, edgeRight;
	int marginWidth, marginHeight;

protected:
	CWnd *m_pWnd, *m_pCtrl;
	BOOL repaintCtrl;
};
